package com.sky.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.context.BaseContext;
import com.sky.dto.OrdersConfirmDTO;
import com.sky.dto.OrdersPaymentDTO;
import com.sky.dto.OrdersPageQueryDTO;
import com.sky.dto.OrdersSubmitDTO;
import com.sky.dto.*;
import com.sky.entity.*;
import com.sky.exception.AddressBookBusinessException;
import com.sky.exception.OrderBusinessException;
import com.sky.mapper.*;
import com.sky.result.PageResult;
import com.sky.service.OrderService;
import com.sky.utils.WeChatPayUtil;
import com.sky.vo.OrderStatisticsVO;
import com.sky.vo.OrderSubmitVO;
import com.sky.vo.OrderVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private ShoppingCartMapper shoppingCartMapper;

    @Autowired
    private AddressBookMapper addressBookMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private WeChatPayUtil weChatPayUtil;

    /**
     * 用户提交订单
     *  1. 订单数据包含订单本身的基本数据和订单的详情数据【买了什么具体的东西】
     *  2. 它们是存储在不同的表里面
     *         订单的基本数据放置在 订单表 orders
     *         订单详情 放置在 订单详情表 order_detail
     *  3. 需要往这两张表添加数据
     *      3.1 先添加订单表 ， 获取到ID，再每一个订单详情里面设置它。
     *      3.2 再添加订单详情表
     *
     * @param dto
     * @return
     */
    @Override
    public OrderSubmitVO add(OrdersSubmitDTO dto) {
        //1. 往订单表添加数据

        //1.0 转化数据模型
        Orders orders = new Orders();
        BeanUtils.copyProperties(dto ,orders);

        //1.1 准备数据
        //1.1.1 准备用户数据
        User user = userMapper.findById(BaseContext.getCurrentId());

        //1.1.2 准备地址数据
        AddressBook addressBook = addressBookMapper.getById(dto.getAddressBookId());

        //如果地址为空，则抛出异常！
        if(addressBook == null){
            throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
        }

        //1.2 补充数据
        fillOrders(orders , addressBook , user);

        //1.3 添加到订单表里面。
        orderMapper.add(orders);


        //2. 往订单详情表添加数据

        //2.1 先获取当前这个用户的购物车数据
        ShoppingCart cart = new ShoppingCart();
        cart.setUserId(BaseContext.getCurrentId());
        List<ShoppingCart> shoppingCartList = shoppingCartMapper.list(cart);

        //2.2 要往订单详情表【order_detail】存数据, 表有对应的实体类： OrderDetail, 所以我们需要把购物车转化成OrderDetail
        // 有多少个购物车对象就要转化出来多少给OrderDetail对象
        List<OrderDetail> orderDetailList = shoppingCartList.stream().map(shoppingCart -> {

            //2.2.1 遍历一次，构建一个新的OrderDetail对象
            OrderDetail od = new OrderDetail();

            //2.2.2 搬运数据
            BeanUtils.copyProperties(shoppingCart, od);

            //2.2.3 设置订单详情属于哪一个订单
            od.setOrderId(orders.getId());

            return od;
        }).collect(Collectors.toList());

        //2.3. 往订单详情表添加数据。
        orderDetailMapper.addAll(orderDetailList);


        //3. 清空购物车
        shoppingCartMapper.deleteByUid(BaseContext.getCurrentId());


        //4. 组建返回的结果：
        return OrderSubmitVO.builder()
                .id(orders.getId())
                .orderNumber(orders.getNumber())
                .orderAmount(orders.getAmount())
                .orderTime(orders.getOrderTime())
                .build();


        /*List<OrderDetail> orderDetailList = new ArrayList<>();
        for (ShoppingCart shoppingCart : shoppingCartList) {

            //2.2.1 遍历一次，就创建一个OrderDetail 对象
            OrderDetail od = new OrderDetail();

            //2.2.2 把购物车数据搬运到od 对象
            BeanUtils.copyProperties(shoppingCart ,od);

            //2.2.3 设置属于哪一个订单
            od.setOrderId(orders.getId());


            // 2.2.4 一边添加到订单详情表 【一个一个的添加...】
            //orderDetailMapper.add(od);

            //TODO:: 打包到一个集合去，一会批量添加。
            orderDetailList.add(od);
        }

        //TODO:: 在这里批量添加
        //orderDetailMapper.addAll(orderDetailList);*/
    }

    /**
     * 再来一单
     *
     * @param id
     */
    public void reAdd(Long id) {
        // 查询当前用户id
        Long userId = BaseContext.getCurrentId();

        // 根据订单id查询当前订单详情
        List<OrderDetail> orderDetailList = orderDetailMapper.getByOrderId(id);

        // 将订单详情对象转换为购物车对象
        List<ShoppingCart> shoppingCartList = orderDetailList.stream().map(m -> {
            ShoppingCart shoppingCart = new ShoppingCart();

            // 将原订单详情里面的菜品信息重新复制到购物车对象中
            BeanUtils.copyProperties(m, shoppingCart, "id");
            shoppingCart.setUserId(userId);
            shoppingCart.setCreateTime(LocalDateTime.now());

            return shoppingCart;
        }).collect(Collectors.toList());

        // 将购物车对象批量添加到数据库
        shoppingCartMapper.insert(shoppingCartList);
    }

    /**
     * @desc TODO:处理订单支付
     * @param dto
     * @return com.sky.vo.OrderSubmitVO
     */
    @Override
    public Orders payment(OrdersPaymentDTO dto) {
        Orders orders = new Orders();
//        BeanUtils.copyProperties(dto ,orders);
        orders.setNumber(dto.getOrderNumber());
        orders.setPayStatus(Orders.PAID);
        orders.setStatus(Orders.TO_BE_CONFIRMED);
        orders.setCheckoutTime(LocalDateTime.now());
        int res = orderMapper.pay(orders);
        if (res >= 1) {
            // 更新完订单状态之后，调用查询订单，获取订单的数据，并把订单的预计送达时间格式化之后返回
           Orders orderInfo =  orderMapper.selectByNumber(Orders.builder().number(dto.getOrderNumber()).build());

           return orderInfo;
       }
        return null;
    }


    /**
     * @desc TODO :用户取消订单
     * @param id
     * @return void
     */
    @Override
    public void userCancelById(Long id) throws Exception {
        // 根据id查询订单
        Orders ordersDB = orderMapper.selectById(id);

        // 校验订单是否存在
        if (ordersDB == null) {
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }

        //订单状态 1待付款 2待接单 3已接单 4派送中 5已完成 6已取消
        if (ordersDB.getStatus() > 2) {
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        Orders orders = new Orders();
        orders.setId(ordersDB.getId());

        // 订单处于待接单状态下取消，需要进行退款
        if (ordersDB.getStatus().equals(Orders.TO_BE_CONFIRMED)) {
            //调用微信支付退款接口
            weChatPayUtil.refund(
                    ordersDB.getNumber(), //商户订单号
                    ordersDB.getNumber(), //商户退款单号
                    new BigDecimal(0.01),//退款金额，单位 元
                    new BigDecimal(0.01));//原订单金额

            //支付状态修改为 退款
            orders.setPayStatus(Orders.REFUND);
        }

        // 更新订单状态、取消原因、取消时间
        orders.setStatus(Orders.CANCELLED);
        orders.setCancelReason("用户取消");
        orders.setCancelTime(LocalDateTime.now());
        orderMapper.update(orders);
    }


    /**
     * 客服端查询订单状态数量
     *
     * @return
     */
    @Override
    public OrderStatisticsVO OrderStatistics() {
        //查询订单状态为待派送的数量
        Integer confirmed = orderMapper.OrderStatistics(Orders.CONFIRMED);

        //查询订单状态为派送中的数量
        Integer deliveryInProgress = orderMapper.OrderStatistics(Orders.DELIVERY_IN_PROGRESS);

        //查询订单状态为待接单的数量
        Integer toBeConfirmed = orderMapper.OrderStatistics(Orders.TO_BE_CONFIRMED);

        //将数据拷贝到vo里面返回给前端
        OrderStatisticsVO orderStatisticsVO = new OrderStatisticsVO();
        orderStatisticsVO.setConfirmed(confirmed);
        orderStatisticsVO.setDeliveryInProgress(deliveryInProgress);
        orderStatisticsVO.setToBeConfirmed(toBeConfirmed);
        return orderStatisticsVO;
    }

    /**
     * 订单搜索
     *
     * @param dto
     * @return
     */
    @Override
    public PageResult selectOrder(OrdersPageQueryDTO dto) {
        //将分页数据放进这个工具类中
        PageHelper.startPage(dto.getPage(),dto.getPageSize());

        //拿到所有的订单数据
        Page<Orders> orders = orderMapper.selectOrder(dto);
        System.out.println(orders.size());
        System.out.println(orders);
        //获取订单表的数量
        long total = orders.getTotal();
        //获取订单表的数据
        List<Orders> ordersList = orders.getResult();
        System.out.println(ordersList);
        //创建一个集合装ordervo
        List<OrderVO>  orderVOList=new ArrayList<>();

        //查询订单详细表数据

        if (ordersList!=null&&ordersList.size()!=0){
            ordersList.forEach(order->{
                //遍历订单表的数据装维ordervo里面
                OrderVO orderVO = new OrderVO();
                BeanUtils.copyProperties(order,orderVO);

                //通过订单id查询出订单详情表的数据
                List<OrderDetail> orderDetails = orderDetailMapper.selectOrderDetail(order.getId());

                //对vo订单详情表赋值
                orderVO.setOrderDetailList(orderDetails);

                //创建一个空的字符串
            /*    StringJoiner stringJoiner = new StringJoiner(",");
                if (orderDetails.size()!=0&&orderDetails!=null){
                    //遍历订单详情表的数据
                    for (OrderDetail orderDetai : orderDetails) {

                        stringJoiner.add(orderDetai.getName()+"*"+orderDetai.getNumber());
                    }
                }*/
                String stringJoiner = orderDetails.stream().map(order1 -> {
                    return order1.getName() + "*" + order1.getNumber();
                }).collect(Collectors.joining(","));

                orderVO.setOrderDishes(stringJoiner);
                orderVOList.add(orderVO);

                System.out.println(orderVOList);
            });
        }



        return new PageResult(total,orderVOList);
    }

    /**
     * 通过订单id查询订单详细信息
     *
     * @param id
     * @return
     */
    @Override
    public OrderVO selectOrderById(Long id) {
        System.out.println(id);
        List<OrderDetail> orderDetailList = orderDetailMapper.selectOrderDetail(id);
        System.out.println(orderDetailList);
        Orders orders = orderMapper.selectById(id);
        System.out.println(orders);
        OrderVO orderVO = new OrderVO();
        BeanUtils.copyProperties(orders,orderVO);
        orderVO.setOrderDetailList(orderDetailList);
        System.out.println(orderVO);
        return orderVO;
    }

    /**
     * 接单
     *
     * @param dto
     */
    @Override
    public void confirm(OrdersConfirmDTO dto) {
        Orders orders = Orders.builder().id(dto.getId())
                .status(Orders.CONFIRMED)
                .build();
        orderMapper.update(orders);
    }

    /**
     * 拒单
     *
     * @param dto
     */
    @Override
    public void rejection(OrdersRejectionDTO dto) {
        // 根据id查询订单
        Orders orders = orderMapper.getById(dto.getId());
        // 拒单需要退款，根据订单id更新订单状态、拒单原因、取消时间
        orders.setId(dto.getId());
        orders.setStatus(Orders.CANCELLED);
        orders.setRejectionReason(dto.getRejectionReason());


        orderMapper.OrderRejection(orders);
    }

    /**
     * 取消订单
     *
     * @param dto
     */
    @Override
    public void cancel(OrdersCancelDTO dto) {
        // 根据id查询订单
        Orders orders1 = orderMapper.getById(dto.getId());



        // 管理端取消订单需要退款，根据订单id更新订单状态、取消原因、取消时间
        Orders orders = new Orders();
        orders.setId(dto.getId());
        orders.setStatus(Orders.CANCELLED);
        orders.setCancelReason(dto.getCancelReason());
        orders.setCancelTime(LocalDateTime.now());
        orderMapper.OrderCancel(orders);

    }

    /**
     * 派送订单
     *
     * @param id
     */
    @Override
    public void delivery(Long id) {
        // 根据id查询订单
        Orders ordersDB = orderMapper.getById(id);

        Orders orders = new Orders();
        orders.setId(ordersDB.getId());
        // 更新订单状态,状态转为派送中
        orders.setStatus(Orders.DELIVERY_IN_PROGRESS);

        orderMapper.delivery(orders);

    }

    /**
     * 完成订单
     *
     * @param id
     */
    @Override
    public void complete(Long id) {
        // 根据id查询订单
        Orders ordersDB = orderMapper.getById(id);


        Orders orders = new Orders();
        orders.setId(ordersDB.getId());
        // 更新订单状态,状态转为完成
        orders.setStatus(Orders.COMPLETED);
        orders.setDeliveryTime(LocalDateTime.now());

        orderMapper.complete(orders);
    }


    /**
     * 填充订单数据
     * @param orders
     * @param addressBook
     * @param user
     */
    private void fillOrders(Orders orders , AddressBook addressBook , User user){
        //1.2.1 设置id :: 自增ID，不用设置
        //1.2.2 设置number 订单号（时间+地区城市+编号...） UUID
        orders.setNumber(UUID.randomUUID().toString().replace("-",""));
        //订单的状态：1: 待付款
        orders.setStatus(Orders.PENDING_PAYMENT);
        //1.2.3 设置user_id 用户ID
        orders.setUserId(BaseContext.getCurrentId());
        //1.2.4 设置address_book_id:: 页面有提供不用设置！
        //1.2.5 设置order_time:: 下单时间
        orders.setOrderTime(LocalDateTime.now());
        //1.2.6 设置checkout_time:: 付款时间，不知道，后续更新它
        //1.2.7 设置pay_method:: 支付方式，下单才知道。后续要更新它
        //1.2.8 设置pay_status:: 支付状态： 0 未支付， 1已支付， 2退款
        orders.setPayStatus(Orders.UN_PAID);
        //1.2.9 设置amount:: 订单总金额，页面提供
        //1.2.10 设置remark:: 备注，前端提供
        //1.2.11 设置phone::  收货人电话，需要设置
        orders.setPhone(addressBook.getPhone());
        //1.2.12 设置address :: 收货人地址，需要设置
        String address = addressBook.getProvinceName() + addressBook.getCityName() + addressBook.getDistrictName() + addressBook.getDetail();
        orders.setAddress(address);
        //1.2.13 设置user_name :: 下单的这个用户的昵称
        orders.setUserName(user.getName());
        //1.2.14 设置consignee :: 收货人姓名
        orders.setConsignee(addressBook.getConsignee());
        //1.2.15 设置cancel_reason :: 取消订单的原因，后续更新它
        //1.2.16 设置rejection_reason:: 拒绝订单的原因， 后续更新它
        //1.2.17 设置estimatedDeliveryTime :: 页面提供，不用设置
        //1.2.18 设置delivery_status:: 配送状态 页面提供，不用设置
        //1.2.18 设置delivery_time:: 送达时间，后续需要更新它
        //1.2.19 设置pack_amount :: 打包费，页面提供不用设置
        //1.2.20 设置tablewareNumber:: 餐具数量，页面提供，不用设置
        //1.2.21 设置tablewareStatus :: 餐具数量状态，页面提供，不用设置
    }


}
